package com.ttbj.product.zwrefund.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.jdom.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ttbj.api.dto.Page;
import com.ttbj.api.dto.zwrefund.ZwRefundDto;
import com.ttbj.api.exception.BusinessException;
import com.ttbj.api.zwrefund.ZwPayTypeEnum;
import com.ttbj.api.zwrefund.ZwRefundCodeEnum;
import com.ttbj.api.zwrefund.ZwRefundService;
import com.ttbj.constant.PlatFormErrorCode;
import com.ttbj.constant.annotation.SystemServiceLog;
import com.ttbj.constant.order.OrderDeleteEnum;
import com.ttbj.core.util.DateUtils;
import com.ttbj.order.dao.OrderMapper;
import com.ttbj.order.dao.OrderWorkMapper;
import com.ttbj.order.dao.WaybillMapper;
import com.ttbj.product.zwrefund.wxpay.CertHttpUtil;
import com.ttbj.product.zwrefund.wxpay.ConfigUtil;
import com.ttbj.product.zwrefund.wxpay.HttpUtil;
import com.ttbj.product.zwrefund.wxpay.PayCommonUtil;
import com.ttbj.product.zwrefund.wxpay.XMLUtil;
import com.ttbj.product.zwrefund.zfbpay.AliPayUtil;
import com.ttbj.zwrefund.dao.ZwRefundMapper;


@Service("zwRefundService")
public class ZwRefundServiceImpl implements ZwRefundService{
	
	@Autowired
	private ZwRefundMapper zwRefundMapper;
	@Autowired
	private OrderMapper orderMapper;
	@Autowired
	private OrderWorkMapper orderWorkMapper;
	@Autowired
	private WaybillMapper waybillMapper;
	
	private static Logger LOGGER = LoggerFactory.getLogger(ZwRefundServiceImpl.class);

	@Override
	public List<ZwRefundDto> findZwRefundInfoByPage(String refundOrderNum, String refundPayNum, Integer[] refundCode, Page page) throws BusinessException {
		List<ZwRefundDto> zwRefundDtos = this.zwRefundMapper.queryZwRefundInfoByPage(refundOrderNum,refundPayNum, refundCode, page);
		return zwRefundDtos;
	}

	@Override
	public Integer findZwRefundInfoByPageCount(String refundOrderNum, String refundPayNum, Integer[] refundCode) throws BusinessException {
		Integer count = this.zwRefundMapper.queryZwRefundInfoByPageCount(refundOrderNum,refundPayNum, refundCode);
		return count;
	}

	@Override
	@Transactional
	@SystemServiceLog(description="微信、支付宝退款")
	public void zwRefundOperation(Integer refundType, String refundAmt, String refundPayNum, Integer refundId, Long orderId) throws BusinessException {
		ZwRefundDto zwRefundDto = new ZwRefundDto();
		Integer refundCode = ZwRefundCodeEnum.Unaudited.getCode();	//审核状态，初始为未审核
		String refundRefundNo = null;	//退款后的退款编号
		Date refundSucDate = null;	//退款时间

		if (Integer.valueOf(refundAmt) <= 0) {	//如果是退款金额是0，则表示此单为未支付单
			refundCode = ZwRefundCodeEnum.Audit_Pass.getCode();	//直接设置此单通过审核
		}else {	//否则进行正常退款
			if (ZwPayTypeEnum.WX.getCode() == refundType) {	//如果是微信支付
				Map<String, String> map = requestWxRefund(refundAmt, refundPayNum);
				if (map != null) {
					String returnCode = map.get("return_code");	//SUCCESS/FAIL：此字段是通信标识，表示接口层的请求结果，并非退款状态。
					if ("SUCCESS".equals(returnCode)) {
						if ("SUCCESS".equals(map.get("result_code"))) {		//result_code：当return_code为SUCCESS的时候有返回
							refundRefundNo = map.get("refund_id");	//设置返回的微信退款单号（refund_id）
							Map<String, String> queryMap = requestWxRefundQuery(refundRefundNo, null);	//调用微信退款查询接口，查询退款状态
							refundCode = Integer.valueOf(queryMap.get("code"));	//设置refundCode的值
							try {
								refundSucDate = queryMap.get("sucDate")== null? null: DateUtils.getStr2Date(queryMap.get("sucDate"), null);
							} catch (ParseException e) {
								e.printStackTrace();
							}
						}else {
							LOGGER.info("微信退款业务信息有误，result_code：{}，err_code：{}，err_code_des：{}", 
														map.get("result_code"), map.get("err_code"), map.get("err_code_des"));
							throw new BusinessException(map.get("err_code_des"), PlatFormErrorCode.DATA_SECURITY.code());
						}
					}else {
						LOGGER.info("微信退款返回了错误信息，信息是：{}", map.get("return_msg"));
						throw new BusinessException("请求失败，重新请求", PlatFormErrorCode.DATA_SECURITY.code());
					}
				}
			}else if (ZwPayTypeEnum.ZFB.getCode() == refundType) {	//如果是支付宝支付
				AlipayTradeRefundResponse response = AliPayUtil.refundOrder(refundPayNum, refundAmt);	//请求支付宝进行退款
				if (response != null && response.isSuccess()) {	//如果不等于空且调用成功
					refundRefundNo = response.getTradeNo();	//设置返回的支付宝交易号（trade_no）
					//退款完成后调用查询接口，查询退款状态
					AlipayTradeFastpayRefundQueryResponse queryResponse = AliPayUtil.refundOrerQuery(refundRefundNo,response.getOutTradeNo());
					if (queryResponse.getRefundAmount() !=null) {
						refundCode = ZwRefundCodeEnum.Audit_Pass.getCode();	//设置成审核通过
						refundSucDate = response.getGmtRefundPay();	//获取退款支付时间
					}else {
						refundCode = ZwRefundCodeEnum.In_Hand.getCode();	//设置成审核中
					}
					refundRefundNo = queryResponse.getOutRequestNo();	//获取out_request_no
				}else {
					LOGGER.info("支付宝退款返回了错误信息，code：{}，msg：{}，sub_code：{}，sub_msg：{}", 
												response.getCode(),response.getMsg(),response.getSubCode(),response.getSubMsg());
					throw new BusinessException(response.getSubMsg(), PlatFormErrorCode.DATA_SECURITY.code());
				}
			}else {
				throw new BusinessException("操作错误", PlatFormErrorCode.DATA_SECURITY.code());
			}
		}
		
		zwRefundDto.setRefundId(refundId);
		zwRefundDto.setRefundCode(refundCode);	//设置审核状态
		zwRefundDto.setRefundNo(refundRefundNo);	//设置退款后的退款单号
		zwRefundDto.setRefundSuccessTime(refundSucDate);	//退款成功时间
		zwRefundDto.setRefundAuditTime(new Date());	//设置审核时间
		int result = this.zwRefundMapper.updateZwRefundInfo(zwRefundDto);
		if (result == 0 ) {
			throw new BusinessException("操作错误", PlatFormErrorCode.DATA_INSERT_ERROR.code());
		}
		this.orderMapper.updateOrderIsDel(OrderDeleteEnum.del.getCode(), orderId);	//设置订单表（ttbj_order）中设置为删除状态
		this.orderWorkMapper.updateOrderWorkIsDel(OrderDeleteEnum.del.getCode(), orderId);	//设置分配给业务员表（ttbj_work）中设置为删除状态
		this.waybillMapper.updateWayBillIsDel(OrderDeleteEnum.del.getCode(), orderId);	//设置分配给司机表（ttbj_waybill）中设置为删除状态
	}
	
	/**
	 * 请求微信退款的接口返回xml并封装成map
	 * @param refundAmt 退款金额
	 * @param refundPayNum 退款的订单号（支付完成后返回来的支付单号）
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Map<String, String> requestWxRefund(String refundAmt, String refundPayNum) {
		BigDecimal amtDecimal = new BigDecimal(refundAmt).multiply(new BigDecimal(100));	//将金额转为分
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		ConfigUtil.wxCommomParams(packageParams);	//封住微信请求的公共参数如 appid等
		packageParams.put("transaction_id", refundPayNum);	//微信生成的订单号，在支付通知中有返回
		packageParams.put("total_fee", amtDecimal.setScale(0).toString());	//订单金额
		packageParams.put("refund_fee", amtDecimal.setScale(0).toString());	//退款金额
		packageParams.put("out_refund_no", UUID.randomUUID().toString().replace("-", ""));
		String sign = PayCommonUtil.createSign("UTF-8", packageParams, ConfigUtil.API_KEY);	//设置签名
		packageParams.put("sign", sign); // 签名
		String requestXML = PayCommonUtil.getRequestXml(packageParams);	//将请求参数转换为xml格式
		String resXML = null;
		try {
			resXML = CertHttpUtil.postData(ConfigUtil.REFUND_URL, requestXML, ConfigUtil.MCH_ID, 
												this.getClass().getResource("/wxcert/apiclient_cert.p12").getPath());	//请求退款接口
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		Map<String, String> map = null;
		try {
			map = XMLUtil.doXMLParse(resXML);	//把返回来的xml解析成map
		} catch (JDOMException | IOException e) {
			e.printStackTrace();
		}
		return map;
	}
	
	/**
	 * 提交退款申请后，通过调用该接口查询退款状态
	 * @param refundPayNum
	 * @return
	 */
	@SuppressWarnings({ "unused", "unchecked" })
	private Map<String, String> requestWxRefundQuery(String refundId, String refundPayNum){
		Map<String, String> responseMap = null;
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		ConfigUtil.wxCommomParams(packageParams);	//封住微信请求的公共参数如 appid等
		if (StringUtils.isNotBlank(refundId)) {
			packageParams.put("refund_id", refundId);	//微信退款单号（refund_id）
		}
		if (StringUtils.isNotBlank(refundPayNum)) {
			packageParams.put("transaction_id", refundPayNum);	//微信订单号（transaction_id）
		}
		String sign = PayCommonUtil.createSign("UTF-8", packageParams, ConfigUtil.API_KEY);		//设置签名
		packageParams.put("sign", sign); // 签名
		String requestXML = PayCommonUtil.getRequestXml(packageParams);	//将请求参数转换为xml格式
		String resXml = HttpUtil.postData(ConfigUtil.REFUND_QUERY_URL, requestXML);
		LOGGER.info("请求微信退款查询接口返回的XML：{}", resXml);
		Map<String, String> map = null;
		try {
			map = XMLUtil.doXMLParse(resXml);	//把返回来的xml解析成map
		} catch (Exception e) {
			e.printStackTrace();
		}	
		Integer code = null;
		if (null != map && map.get("result_code").equals("SUCCESS")) {
			responseMap = new HashMap<>();
			String refundStats = map.get("refund_status_0");	//获取退款查询后返回的退款状态
			switch (refundStats) {
			case "SUCCESS":	//成功
				code = ZwRefundCodeEnum.Audit_Pass.getCode();
				break;
			case "REFUNDCLOSE" :	//退款关闭
				code = ZwRefundCodeEnum.Closed.getCode();
				break;
			case "PROCESSING" :	//退款处理中
				code = ZwRefundCodeEnum.In_Hand.getCode();
				break;
			case "CHANGE" :	//退款异常
				code = ZwRefundCodeEnum.Abnormal.getCode();
				break;
			}
//			responseMap.put("refundId", map.get("refund_id_0"));
			responseMap.put("code", String.valueOf(code));	//转换
			responseMap.put("sucDate", map.get("refund_success_time_0"));	//获取退款成功时间
		}
		return responseMap;
	}

	@Override
	@Transactional
	@SystemServiceLog(description="退款设置为未通过")
	public void editRefundAuditFailed(Integer refundCode, Integer refundId, Long orderId) throws BusinessException {
		if (null == refundId || null==orderId) {
			throw new BusinessException("非法操作", PlatFormErrorCode.DATA_SECURITY.code());
		}
		ZwRefundDto zwRefundDto = new ZwRefundDto();
		zwRefundDto.setRefundCode(refundCode);
		zwRefundDto.setRefundId(refundId);
		zwRefundDto.setRefundAuditTime(new Date());
		//执行更改操作
		int result = this.zwRefundMapper.updateZwRefundInfo(zwRefundDto);
		if (result == 0) {
			LOGGER.info("更改为未通过状态时出现错误，更改失败");
			throw new BusinessException("更改失败", PlatFormErrorCode.DATA_SECURITY.code());
		}
		this.orderMapper.updateOrderIsDel(OrderDeleteEnum.del.getCode(), orderId);	//设置订单表（ttbj_order）中设置为删除状态
		this.orderWorkMapper.updateOrderWorkIsDel(OrderDeleteEnum.del.getCode(), orderId);	//设置分配给业务员表（ttbj_work）中设置为删除状态
		this.waybillMapper.updateWayBillIsDel(OrderDeleteEnum.del.getCode(), orderId);	//设置分配给司机表（ttbj_waybill）中设置为删除状态
	}

	@Override
	@Transactional
	public Integer wxRefundQuery(String refundPayNum, Integer refundCode, Integer refundId) throws BusinessException {
		Map<String, String> map =  requestWxRefundQuery(null, refundPayNum);	//微信查询退款
		if (null == map) {
			throw new BusinessException("查询失败", PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code()); 
		}
		Integer code = Integer.valueOf(map.get("code"));	//获取转换后的状态
		if (code != refundCode) {	//如果传来的退款状态跟查询后的状态不相同，则更新数据库里的状态
			String suc_date = map.get("sucDate");	//获取退款成功的时间
			ZwRefundDto refundDto = new ZwRefundDto();
			refundDto.setRefundId(refundId);
			refundDto.setRefundCode(code);
			try {
				refundDto.setRefundSuccessTime(suc_date==null?null:DateUtils.getStr2Date(suc_date, null));
			} catch (ParseException e) {
				e.printStackTrace();
			}
			int result = this.zwRefundMapper.updateZwRefundInfo(refundDto);	//更新数据库里的状态
		}
		return code;	//返回退款状态标识
	}

	@Override
	@Transactional
	public Integer zfbRefundQuery(String refundPayNum, String outTradeNo, Integer refundCode, Integer refundId) throws BusinessException {
		AlipayTradeFastpayRefundQueryResponse response = AliPayUtil.refundOrerQuery(refundPayNum, outTradeNo);
		if (!response.getCode().equals("10000")) {	//如果返回的code不为10000，则说明支付宝接口调用失败
			throw new BusinessException(response.getSubMsg(), PlatFormErrorCode.OBJECT_DOES_NOT_EXIST.code()); 
		}else {
			if (response.getTradeNo() != null) {
				if (refundCode != ZwRefundCodeEnum.Audit_Pass.getCode()) {	//如果数据库的状态不是审核通过，则更改
					ZwRefundDto refundDto = new ZwRefundDto();
					refundDto.setRefundId(refundId);
					refundDto.setRefundCode(ZwRefundCodeEnum.Audit_Pass.getCode());	//设置成审核通过
					int result = this.zwRefundMapper.updateZwRefundInfo(refundDto);	//更新数据库里的状态
				}
				return ZwRefundCodeEnum.Audit_Pass.getCode();	//返回退款状态标识
			}else {
				throw new BusinessException("查询失败，请保证退款号正确", PlatFormErrorCode.DATA_SECURITY.code());
			}
		}
	}
}
